package com.github.zyf.ioaj.algorithm;

import com.github.zyf.ioaj.constant.FileType;
import com.github.zyf.ioaj.constant.ParamType;
import com.github.zyf.ioaj.annotation.internal.*;
import com.github.zyf.ioaj.export.Report;
import com.github.zyf.ioaj.export.Tracker;

/**
 * <h1>算法抽象类</h1>
 * <p>每一个待实现的算法都要直接或间接继承这个类</p>
 * <p>需要计算则调用{@link #go()}</p>
 * <p>需要跟踪每次迭代则调用{@link #tracker(String, String, String, FileType)}</p>
 * <p>需要生成报告则调用{@link #report(String, String, String, FileType)}</p>
 * <p>注1：所有算法都默认求最小值，如果需要求解最大值，将目标函数乘以-1即可，最后得到的值再次乘以-1就是得到的最优值（自变量取值不用乘以-1）</p>
 * <p>注2：保证所有参数属性在添加对应的注解之前，实现了对应的get方法（普通变量的get方法get开头，布尔型变量的get方法is开头）</p>
 * <p>
 * 注3：{@link #tracker(String, String, String, FileType)}方法的开销非常大，要慎用（建议非学习、演示或Debug，不要使用）。
 * 因为每次迭代都需要进行相应的记录，记录的方式借助了Java反射机制，在迭代次数很大时，资源消耗异常大
 * </p>
 * <h2>算法编写约定</h2>
 * <p>为了统一算法，这里约定算法类编写的规范，具体如下</p>
 * <ol>
 *     <li>所有算法参数（类全局变量）都要是封装类，以保证不能存在未初始化的情况</li>
 *     <li>所有Getter/Setter方法全部放在类末尾，辅助函数放在Getter/Setter区域上面</li>
 *     <li>一个算法包括一层迭代的循环，单词迭代的循环封装成一个函数，一次迭代拆分成若干步骤</li>
 * </ol>
 *
 * @author zyf
 */
@Algorithm
public abstract class AbstractAlgorithm {

    /**
     * 算法输入量，{@link Input}
     */
    @InputParam(type = ParamType.OBJECT)
    private final Input input;

    /**
     * 算法输出量，{@link Output}
     */
    @OutputParam(type = ParamType.OBJECT)
    private Output output;

    /**
     * 迭代次数
     */
    @BasicParam(type = ParamType.INT, desc = "迭代次数")
    private int iter;

    /**
     * 抽象算法构造函数，需要提供输入量，即提前初始化好{@link Input}对象
     *
     * @param input {@link #input}
     */
    public AbstractAlgorithm(Input input) {
        this.input = input;
        this.iter = 100;
    }

    /**
     * 运行并计算结果
     */
    public abstract void go();

    /**
     * <p>运行并计算结果（按迭代逐步跟踪，自带运行，无需手动），如果目的是计算出结果，请使用{@link #go()}</p>
     * <p>如果需要使用，非特殊要求，建议迭代次数设置为100或以下，否则后果自负</p>
     *
     * @param author   作者
     * @param message  备注
     * @param title    标题
     * @param fileType 文件类型 {@link FileType}
     * @return {@link Tracker}
     */
    public abstract Tracker tracker(String author, String message, String title, FileType fileType);

    /**
     * 生成报告（要先手动运行才能生成报告）
     *
     * @param author   作者
     * @param message  备注
     * @param title    标题
     * @param fileType 文件类型 {@link FileType}
     * @return {@link Report}
     */
    public abstract Report report(String author, String message, String title, FileType fileType);

    public Input getInput() {
        return input;
    }

    public Output getOutput() {
        return output;
    }

    public void setOutput(Output output) {
        this.output = output;
    }

    public int getIter() {
        return iter;
    }

    public void setIter(int iter) {
        this.iter = iter;
    }
}
